﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Configuration.Install;

namespace Amie.Utils
{
  public class Service
  {
    private readonly string _username;
    private readonly string _password;
    private readonly string _serviceName;

    public Service()
    {
    }

    public Service(string serviceName, string username, string password)
    {
      _username = username;
      _password = password;
      _serviceName = serviceName;
    }

    private ServiceController _serviceController;
    private  ServiceController ServiceController
    {
      get {
        return _serviceController ?? (_serviceController = new ServiceController(_serviceName, System.Environment.MachineName));
      }
    }

    private bool ServiceExists()
    {
      try
      {
        if (ServiceController.Status == ServiceControllerStatus.Running | ServiceController.Status == ServiceControllerStatus.Stopped)
        {
          return true;
        }
      }
      catch (Exception ex)
      {
        return false;
      }
      return false;
    }

    public ServiceControllerStatus ServiceStatus
    {
      get
      {
        return ServiceController.Status;
      }
    }

    public List<string> GetServiceAccountTypes()
    {
      return Enum.GetNames(typeof (ServiceAccount)).ToList();
    }

    /// <summary>
    /// If the service exists it will be stopped, uninstall, and install from the path.  
    /// If the service does not exist then it will be installed.
    /// </summary>
    /// <param name="runPath">The path from where the service will run.  This is the path of the service.exe</param>
    /// <param name="accountType">If user make sure that the username and password are corrected when this obj is initilized</param>
    /// <param name="displayName"></param>
    /// <param name="description"></param>
    /// <param name="serviceName"></param>
    public void Install(string runPath, ServiceAccount accountType, string displayName, string description)
    {
      if (ServiceExists())
      {
        StopService();
        UninstallService();
      }
      InstallService(runPath,accountType,displayName,description);
      StartService();
    }

    public void Uninstall()
    {
      if (!ServiceExists()) return;
      StopService();
      UninstallService();
    }

    private void InstallService(string runPath, ServiceAccount accountType, string displayName, string description)
    {
      var procesServiceInstaller = new ServiceProcessInstaller();
      if (accountType == ServiceAccount.User)
      {
        procesServiceInstaller.Account = ServiceAccount.User;
        procesServiceInstaller.Username = _username;
        procesServiceInstaller.Password = _password;
      }
      else
      {
        procesServiceInstaller.Account = accountType;
      }

      var serviceInstallerObj = new ServiceInstaller();

      string path = string.Format("/assemblypath={0}", runPath);
      string[] cmdline = { path };

      var context = new InstallContext("", cmdline);
      serviceInstallerObj.Context = context;
      serviceInstallerObj.DisplayName = displayName;
      serviceInstallerObj.Description = description;
      serviceInstallerObj.ServiceName = _serviceName;
      serviceInstallerObj.StartType = ServiceStartMode.Automatic;
      serviceInstallerObj.Parent = procesServiceInstaller;

      var state = new System.Collections.Specialized.ListDictionary();
      serviceInstallerObj.Install(state);
    }

    private void UninstallService()
    {
      var si = new ServiceInstaller();
      var context = new InstallContext(null, null);
      si.Context = context;
      si.ServiceName = _serviceName;
      si.Uninstall(null);
    }

    public bool StartService()
    {
      if (!ServiceExists()) return false;
      if (ServiceController.Status == ServiceControllerStatus.Stopped)
      {
        ServiceController.Start();
        return true;
      }
      else
      {
        return true;
      }
    }

    public bool StopService()
    {
      if (!ServiceExists()) return false;
      if (ServiceController.Status != ServiceControllerStatus.Running) return false;
      if ((ServiceController.CanStop))
      {
        ServiceController.Stop();
        return true;
      }
      else
      {
        return false;
      }
    }
  }
}


